import SyntaxHighlighter from 'components/SyntaxHighlighter'
import PropsTable from 'components/PropsTable'

## Introduction

The `SelectMenu` component is an advanced interaction pattern which allows selection of multiple items from a dropdown list.
It can be used as a substitute for the native multiple select element.


### Implementation details

The `SelectMenu` builds on top of the `Popover` component
and uses `react-tiny-virtual-list` for the rendering of the virtualized list of options.


## Multiselect

The `SelectMenu` is unopinionated in how many items are selected in the list.
Pass an array to the `selected` prop to select more items.

## Close on select

The `SelectMenu` by default will stay open when an option is selected.
This can be configured so that the menu closes on selection.
This will not apply for Multiselect menus.

## Options prop structure

```js static
const options = [
  {
    label: 'String',
    value: 'String or Number'
  }
]
```

## Single selected item

This example shows basic usage with a single selected item.

```jsx
<Component initialState={{ selected: null }}>
  {({ setState, state }) => (
    <SelectMenu
      title="Select name"
      options={
        ['Apple', 'Apricot', 'Banana', 'Cherry', 'Cucumber']
          .map(label => ({ label, value: label }))
      }
      selected={state.selected}
      onSelect={item => setState({ selected: item.value })}
    >
      <Button>{state.selected || 'Select name...'}</Button>
    </SelectMenu>
  )}
</Component>
```

## Remove title and filter

* `hasFilter={false}`:  to remove the search input filter.
* `hasTitle={false}`:  to remove the title from the popover.

```jsx
<Component initialState={{ selected: null }}>
  {({ setState, state }) => (
    <SelectMenu
      hasTitle={false}
      hasFilter={false}
      title="Select name"
      options={
        ['Apple', 'Apricot', 'Banana', 'Cherry', 'Cucumber']
          .map(label => ({ label, value: label }))
      }
      selected={state.selected}
      onSelect={item => setState({ selected: item.value })}
    >
      <Button>{state.selected || 'Select name...'}</Button>
    </SelectMenu>
  )}
</Component>
```

## Change the height and width

```jsx
<Component initialState={{ selected: null }}>
  {({ setState, state }) => (
    <SelectMenu
      height={140}
      width={180}
      hasTitle={false}
      hasFilter={false}
      title="Select name"
      options={
        ['Apple', 'Apricot', 'Banana', 'Cherry', 'Cucumber']
          .map(label => ({ label, value: label }))
      }
      selected={state.selected}
      onSelect={item => setState({ selected: item.value })}
    >
      <Button>{state.selected || 'Select name...'}</Button>
    </SelectMenu>
  )}
</Component>
```

## Change the position of the popover

Available positions:

* `Position.TOP`
* `Position.TOP_LEFT`
* `Position.TOP_RIGHT`
* `Position.BOTTOM`
* `Position.BOTTOM_LEFT`
* `Position.BOTTOM_RIGHT`

```jsx
<Component initialState={{ selected: null }}>
  {({ setState, state }) => (
    <SelectMenu
      position={Position.TOP}
      title="Select name"
      options={
        ['Apple', 'Apricot', 'Banana', 'Cherry', 'Cucumber']
          .map(label => ({ label, value: label }))
      }
      selected={state.selected}
      onSelect={item => setState({ selected: item.value })}
    >
      <Button>{state.selected || 'Select name...'}</Button>
    </SelectMenu>
  )}
</Component>
```

## Empty view

It's possible to display a custom empty view instead of options list via `emptyView`, when there are no properties supplied.
Note that empty view won't be shown when options are being filtered and there are no search results.

```jsx
<SelectMenu
  title="Empty view"
  options={[]}
  emptyView={(
    <Pane height="100%" display="flex" alignItems="center" justifyContent="center">
      <Text size={300}>No options found</Text>
    </Pane>
  )}
>
  <Button>Select option...</Button>
</SelectMenu>
```

It's also possible to close `<SelectMenu>` from within empty view:

```jsx
<SelectMenu
  title="Empty view"
  options={[]}
  emptyView={({ close }) => (
    <Pane height="100%" display="flex" alignItems="center" justifyContent="center">
      <Button onClick={close}>Close</Button>
    </Pane>
  )}
>
  <Button>Select option...</Button>
</SelectMenu>
```

## Menu with icons

It's possible to include icons in the menu list.

```jsx
<SelectMenu
  title="Options with icons"
  options={[
    { label: 'Apple', value: 'Apple', icon: 'https://upload.wikimedia.org/wikipedia/commons/d/d2/Malus-Boskoop_organic.jpg' },
    { label: 'Banana', value: 'Banana', icon: 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Bananas_white_background_DS.jpg/2560px-Bananas_white_background_DS.jpg' },
  ]}
>
  <Button>Select option...</Button>
</SelectMenu>
```


## Multiselect with deselect example

This example shows usage with multiple selected items.

This pattern is only an example.
Selected values and the formatting of their names should be managed wherever you choose to manage state.
The `onDeselect` method is provided to assist with this.

As users click on selected values to remove them, you can update state.


```jsx
<Component
  initialState={{
    options: ['Apple', 'Apricot', 'Banana', 'Cherry', 'Cucumber']
          .map(label => ({ label, value: label })),
    selected: []
  }}
>
  {({ state, setState }) => (
    <SelectMenu
      isMultiSelect
      title="Select multiple names"
      options={state.options}
      selected={state.selected}
      onSelect={item => {
        const selected = [...state.selected, item.value]
        const selectedItems = selected
        const selectedItemsLength = selectedItems.length
        let selectedNames = ''
        if (selectedItemsLength === 0) {
          selectedNames = ''
        } else if (selectedItemsLength === 1) {
          selectedNames = selectedItems.toString()
        } else if (selectedItemsLength > 1) {
          selectedNames = selectedItemsLength.toString() + ' selected...'
        }
        setState({
          selected,
          selectedNames
        })
      }}
      onDeselect={item => {
        const deselectedItemIndex = state.selected.indexOf(item.value)
        const selectedItems = state.selected.filter(
          (_item, i) => i !== deselectedItemIndex
        )
        const selectedItemsLength = selectedItems.length
        let selectedNames = ''
        if (selectedItemsLength === 0) {
          selectedNames = ''
        } else if (selectedItemsLength === 1) {
          selectedNames = selectedItems.toString()
        } else if (selectedItemsLength > 1) {
          selectedNames = selectedItemsLength.toString() + ' selected...'
        }
        setState({ selected: selectedItems, selectedNames })
      }}
    >
      <Button>{state.selectedNames || 'Select multiple...'}</Button>
    </SelectMenu>
  )}
</Component>
```

## onFilterChange example

This example shows basic usage with onFocusChange.

```jsx
<Component initialState={{ selected: null }}>
  {({ setState, state }) => (
    <Pane>
    <Pane marginBottom={8}>
      <Text>Filter value: {state.filter}</Text>
    </Pane>
    <SelectMenu
      title="Select name"
      onFilterChange={filter => setState({filter})}
      options={
        ['Apple', 'Apricot', 'Banana', 'Cherry', 'Cucumber']
          .map(label => ({ label, value: label }))
      }
      selected={state.selected}
      onSelect={item => setState({ selected: item.value })}
    >
      <Button>{state.selected || 'Select name...'}</Button>
    </SelectMenu>
    </Pane>
  )}

</Component>
```

## Disabled option example

This example shows basic usage for disabling some options. Options that are disabled cannot be clicked and their labels are muted.

```jsx
<Component initialState={{ selected: null }}>
  {({ setState, state }) => (
    <Pane>
    <SelectMenu
      title="Select Option"
      options={
        [{ label: "Disabled", value: "disabled", disabled: true }, { label: "Not Disabled", value: "not-disabled" }]
      }
      selected={state.selected}
      onSelect={item => setState({ selected: item.value })}
    >
      <Button>{state.selected || 'Select name...'}</Button>
    </SelectMenu>
    </Pane>
  )}

</Component>
```
## Custom Title Example

This example shows how one should use titleView to pass in a custom title.

```jsx
<Component initialState={{ selected: null }}>
  {({ setState, state }) => (
    <Pane>
    <SelectMenu
      title="Select Option"
      tooltipContent="Choose one of the options below."
      titleView={({ close, title, headerHeight }) => {
        return (
          <Pane
            display="flex"
            alignItems="center"
            borderBottom="default"
            padding={8}
            height={headerHeight}
            boxSizing="border-box"
          >
            <Pane flex="1" display="flex" alignItems="center">
              <Heading size={400}>{title}</Heading>
                <Tooltip content="Pick one of the options below">
                  <Icon size={12} marginLeft={4} icon="help" />
                </Tooltip>
            </Pane>
            <IconButton
              icon="cross"
              appearance="minimal"
              height={24}
              onClick={close}
            />
          </Pane>
        )
      }}
      options={
        [{ label: "Option 1", value: "option-1"}, { label: "Option 2", value: "option-2" }]
      }
      selected={state.selected}
      onSelect={item => setState({ selected: item.value })}
    >
      <Button>{state.selected || 'Select name...'}</Button>
    </SelectMenu>
    </Pane>
  )}

</Component>
```

## Custom Filter PlaceHolder and Icon Example

It's possible to change the filter placeholder and filter icon through the `filterPlaceholder` and `filterIcon` props.

Note that the icon can be one found in Segment's various [icons](https://evergreen.segment.com/components/icons), or `none`.


```jsx
<Component initialState={{ selected: null }}>
  {({ setState, state }) => (
    <SelectMenu
      title="Select name"
      options={
        ['Comedy', 'Drama', 'Fantasy', 'Family', 'Action']
          .map(label => ({ label, value: label }))
      }
      selected={state.selected}
      onSelect={item => setState({ selected: item.value })}
      filterPlaceholder={"Choose a genre"}
      filterIcon={"film"}
    >
      <Button>{state.selected || 'Select name...'}</Button>
    </SelectMenu>
  )}
</Component>
```

<PropsTable of="SelectMenu" />
